#include <iostream>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>

using namespace std;

class Foo {
public:
    Foo() {
       flag = 1; 
    }

    void first(function<void()> printFirst) {
        
            // printFirst() outputs "first". Do not change or remove this line.
            printFirst();
            flag = 2;
            cv.notify_all();
        
        
    }

    void second(function<void()> printSecond) {
        std::unique_lock<std::mutex> uniLock(mtx);
        cv.wait(uniLock,[this]{return flag == 2;});
        
        // printSecond() outputs "second". Do not change or remove this line.
        printSecond();
        flag = 3;
        cv.notify_all();
       
    }
                        
    void third(function<void()> printThird) {
        std::unique_lock<std::mutex> uniLock(mtx);
        cv.wait(uniLock,[this]{return flag == 3;});
        // printThird() outputs "third". Do not change or remove this line.
        printThird();
        flag = 1;
        cv.notify_all();
    }
    private:
        std::atomic<int> flag;
        std::mutex mtx;
        std::condition_variable cv;
};

int main()
{
    Foo f;
    thread t1([&](){f.first([](){cout << "first" << endl;});});
    thread t2([&](){f.second([](){cout << "second" << endl;});});
    thread t3([&](){f.third([](){cout << "third" << endl;});});



    t1.join();
    t2.join();
    t3.join();
}